package com.huihe.common.utils;

import cn.hutool.core.util.StrUtil;
import jakarta.servlet.http.HttpServletRequest;

import java.net.InetAddress;
import java.net.UnknownHostException;

/**
 * IP工具类
 */
public class IpUtils {

    /**
     * 获取客户端IP(根据当前线程的请求)
     * @return IP地址
     */
    public static String getIpAddr() {
        return getIpAddr(ServletUtils.getRequest());
    }

    /**
     * 根据当前的 HttpServletRequest 获取 IP 地址
     * @param request 请求对象
     * @return IP地址
     */
    public static String getIpAddr(HttpServletRequest request) {
        if (request == null) {
            return null;
        }
        String ip = request.getHeader("x-forwarded-for");
        //代理服务器可能会记录原始客户端的IP地址,并存入Proxy-Client-IP
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        //X-Forwarded-For 是一个标准的HTTP头，用于标识原始请求的客户端IP地址
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("X-Forwarded-For");
        }
        //当请求通过WebLogic代理时，它会将原始客户端的IP地址添加到这个头中
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        //X-Real-IP 是一个非标准的HTTP头，通常由反向代理服务器（如Nginx）添加
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("X-Real-IP");
        }
        //是Servlet API提供的方法，用于获取当前请求的客户端IP地址。(无法预防代理服务器)
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        //判断当前IP是否是IPV6的回环地址,并对IP串进行切分
        ip = "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : getMultistageReverseProxyIp(ip);
        if (isValidIPAddress(ip))
            return ip;
        else
            return null;
    }

    /**
     * 从多级反向代理中获得第一个非unknown IP地址
     * 因为请求可能经过代理，携带的IP可能有多个。如:X-Forwarded-For: 192.168.1.1,10.0.0.1
     * @param ip 获得的IP地址
     * @return 第一个非unknown IP地址
     */
    public static String getMultistageReverseProxyIp(String ip) {
        // 多级反向代理检测
        if (ip != null && ip.indexOf(",") > 0) {
            final String[] ips = ip.trim().split(",");
            for (String subIp : ips) {
                if (!isUnknown(subIp)) {
                    ip = subIp;
                    break;
                }
            }
        }
        return ip;
    }

    /**
     * 检测给定字符串是否为未知(unknown)，多用于检测HTTP请求相关
     * @param checkString 被检测的字符串
     * @return 是否未知
     */
    public static boolean isUnknown(String checkString) {
        return StrUtil.isBlank(checkString) || "unknown".equalsIgnoreCase(checkString);
    }

    /**
     * 判断参数String是不是IP
     * @param ip 要判断的字符串
     * @return 结果
     */
    public static boolean isValidIPAddress(String ip) {
        try {
            InetAddress inetAddress = InetAddress.getByName(ip);
            return true;
        } catch (UnknownHostException e) {
            return false;
        }
    }
}
